/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package me.zhengjie.modules.system.service.impl;

import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import me.zhengjie.config.FileProperties;
import me.zhengjie.config.enums.QrCodeTypeEnum;
import me.zhengjie.config.utils.QrCodeUtils;
import me.zhengjie.modules.system.domain.ExamResult;
import me.zhengjie.modules.system.domain.GroupTest;
import me.zhengjie.modules.system.domain.GroupTestDetail;
import me.zhengjie.modules.system.repository.GroupTestRepository;
import me.zhengjie.modules.system.service.AtmrService;
import me.zhengjie.modules.system.service.GroupTestService;
import me.zhengjie.modules.system.service.dto.AtmrDto;
import me.zhengjie.modules.system.service.dto.GroupTestDto;
import me.zhengjie.modules.system.service.dto.GroupTestQueryCriteria;
import me.zhengjie.modules.system.service.mapstruct.GroupTestMapper;
import me.zhengjie.modules.web.service.mybatisplus.IExamResultPlusService;
import me.zhengjie.modules.web.service.mybatisplus.IGroupTestDetailPlusService;
import me.zhengjie.modules.web.service.mybatisplus.IGroupTestPlusService;
import me.zhengjie.utils.*;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.*;

/**
* @website https://el-admin.vip
* @description 服务实现
* @author zhaoxiancheng
* @date 2021-11-21
**/
@Service
@RequiredArgsConstructor
public class GroupTestServiceImpl implements GroupTestService {

    private final GroupTestRepository groupTestRepository;
    private final GroupTestMapper groupTestMapper;

    @Value("${qrcode.url}")
    String qrCodeUrl;

    @Value("${qrcode.authUrl}")
    String qrAuthUrl;

    @Value("${qrcode.child_url}")
    String childQrCodeUrl;

    @Autowired
    FileProperties properties;

    @Autowired
    private AtmrService atmrService;

    @Autowired
    private IGroupTestDetailPlusService groupTestDetailPlusService;

    @Autowired
    private IGroupTestPlusService groupTestPlusService;

    @Autowired
    private IExamResultPlusService examResultPlusService;

    @Override
    public Map<String,Object> queryAll(GroupTestQueryCriteria criteria, Pageable pageable){
        Page<GroupTest> page = groupTestRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(groupTestMapper::toDto));
    }

    @Override
    public Map<String, Object> batchList(GroupTestQueryCriteria criteria, Pageable pageable) {
        Page<GroupTest> page = groupTestRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(groupTestMapper::toDto));
    }

    @Override
    public List<GroupTestDto> queryAll(GroupTestQueryCriteria criteria){
        return groupTestMapper.toDto(groupTestRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public GroupTestDto findById(Integer id) {
        GroupTest groupTest = groupTestRepository.findById(id).orElseGet(GroupTest::new);
        ValidationUtil.isNull(groupTest.getId(),"GroupTest","id",id);
        return groupTestMapper.toDto(groupTest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public GroupTestDto create(GroupTest resources) {
        resources.setLimitUsed(0);
        resources.setCreateBy(SecurityUtils.getCurrentUsername());
        return groupTestMapper.toDto(groupTestRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(GroupTest resources) {
        GroupTest groupTest = groupTestRepository.findById(resources.getId()).orElseGet(GroupTest::new);
        ValidationUtil.isNull( groupTest.getId(),"GroupTest","id",resources.getId());
        groupTest.copy(resources);
        groupTestRepository.save(groupTest);
    }

    @Override
    public void updateV2(GroupTest resources) {
        GroupTest groupTest = groupTestRepository.findById(resources.getId()).orElseGet(GroupTest::new);
        ValidationUtil.isNull( groupTest.getId(),"GroupTest","id",resources.getId());

        AtmrDto atmrDto = atmrService.findById(resources.getAtmrId());
        String qrcodeUrl = qrCodeUrl;
        if (Objects.nonNull(atmrDto) && atmrDto.getAgeType().equals("2")){
            qrcodeUrl = childQrCodeUrl;
        }
        if (Objects.nonNull(resources.getAtmrId()) && !groupTest.getAtmrId().equals(resources.getAtmrId())){
            qrcodeUrl = MessageFormat.format(qrcodeUrl,resources.getAtmrId().toString(),resources.getId().toString());
            String codeUrl = QrCodeUtils.getInstance().generate(qrcodeUrl, QrCodeTypeEnum.GroupTest);
            resources.setQrCode(codeUrl.replace(properties.getPath().getNgx(),""));
        }

        if (Objects.isNull(resources.getOptType())) {
            resources.setOptType(0);
        }
        if (Objects.nonNull(resources.getOptType()) && resources.getOptType() == 1){
            LambdaQueryWrapper<GroupTestDetail> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(GroupTestDetail::getGroupId, resources.getId());
            long count = groupTestDetailPlusService.count(queryWrapper);
            if (count > resources.getQrcodeNum()){
                throw new RuntimeException("二维码总数不能小于已生成数量【"+groupTest.getQrcodeNum()+"】");
            }
            if (count < resources.getQrcodeNum()){
                List<GroupTestDetail> groupTestDetailList = new ArrayList<>();
                for (long i = count; i <= resources.getQrcodeNum(); i++) {
                    GroupTestDetail groupTestDetail = new GroupTestDetail();
                    groupTestDetail.setGroupId(groupTest.getId().longValue());
                    groupTestDetail.setSerialNumber(Integer.parseInt(String.valueOf(i))+1);
                    String groupCode = UUID.fastUUID().toString(true);
                    groupTestDetail.setSerialCode(groupCode);
                    String url = qrcodeUrl + "&groupCode="+groupCode;
                    groupTestDetail.setQrCodeText(url);
                    String content = MessageFormat.format(url,groupTest.getAtmrId().toString(),groupTest.getId().toString());
                    String fileName = QrCodeTypeEnum.GroupTestBatch.getType() + "_"+DateUtil.dateYYYYMMDDHHMMSS(new Date())+"_"+groupTest.getTitle()+ "_编号_" + (i + 1);
                    String codeUrl = QrCodeUtils.getInstance().generate(content, fileName);
                    groupTestDetail.setQrCodeUrl(codeUrl.replace(properties.getPath().getNgx(),""));
                    groupTestDetailList.add(groupTestDetail);
                }
                groupTestDetailPlusService.saveBatch(groupTestDetailList);
            }
        }
        resources.setUpdateBy(SecurityUtils.getCurrentUsername());
        resources.setUpdateTime(new Date());
        groupTest.copy(resources);
        groupTestRepository.save(groupTest);
    }

    @Override
    public void deleteAll(Integer[] ids) {
        for (Integer id : ids) {
            groupTestRepository.deleteById(id);
            groupTestDetailPlusService.remove(new LambdaQueryWrapper<GroupTestDetail>().eq(GroupTestDetail::getGroupId,id));
        }
    }

    @Override
    public void download(List<GroupTestDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (GroupTestDto groupTest : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("标题", groupTest.getTitle());
            map.put("测试类型", groupTest.getAtmrId());
            map.put("人数", groupTest.getLimitNum());
            map.put("已扫码人数", groupTest.getLimitUsed());
            map.put("状态", groupTest.getStatus());
            map.put("二维码", groupTest.getQrCode());
            map.put("有效期-开始", groupTest.getValidityFrom());
            map.put("有效期-结束", groupTest.getValidityTo());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public void download(Long groupId, HttpServletResponse response) throws IOException {
        GroupTest groupTest = groupTestPlusService.getById(groupId);
        if (Objects.isNull(groupTest)){
            throw new RuntimeException("未找到该分组");
        }
        LambdaQueryWrapper<GroupTestDetail> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(GroupTestDetail::getGroupId, groupId);
        List<GroupTestDetail> detailList = groupTestDetailPlusService.list(queryWrapper);
        if (CollectionUtils.isEmpty(detailList)){
            return;
        }
        List<Map<String, Object>> list = new ArrayList<>();
        for (GroupTestDetail detail : detailList) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("标题", groupTest.getTitle());
            map.put("二维码编号", detail.getSerialNumber());
            map.put("测评地址", detail.getQrCodeText());
            list.add(map);
        }
        FileUtil.downloadExcel(list,groupTest.getTitle(), response);
    }

    @Override
    public void exportTestingUser(String groupCode, HttpServletResponse response) throws IOException {
        if (StringUtils.isBlank(groupCode)){
            return;
        }
        LambdaQueryWrapper<GroupTestDetail> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(GroupTestDetail::getSerialCode, groupCode);
        GroupTestDetail groupTestDetail = groupTestDetailPlusService.getOne(queryWrapper);
        if (Objects.isNull(groupTestDetail)){
            return;
        }

        LambdaQueryWrapper<ExamResult> examWrapper = new LambdaQueryWrapper<>();
        examWrapper.eq(ExamResult::getGroupCode, groupCode);
        List<ExamResult> resultList = examResultPlusService.list(examWrapper);

        List<Map<String, Object>> list = new ArrayList<>();
        for (ExamResult result : resultList) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("二维码编号", groupTestDetail.getSerialNumber());
            map.put("姓名", result.getWxRealName());
            map.put("手机号", result.getMobile());
            map.put("openId", result.getWxId());
            map.put("昵称", result.getWxName());
            map.put("特质类型", result.getAtmrResultType());
            map.put("测评时间", result.getExamTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list,UUID.fastUUID().toString(true), response);
    }

    @Override
    public void exportTestingUserV2(Integer groupId, HttpServletResponse response) throws IOException {
        if (Objects.isNull(groupId)){
            return;
        }

        LambdaQueryWrapper<ExamResult> examWrapper = new LambdaQueryWrapper<>();
        examWrapper.eq(ExamResult::getGroupId, groupId);
        List<ExamResult> resultList = examResultPlusService.list(examWrapper);

        List<Map<String, Object>> list = new ArrayList<>();
        for (ExamResult result : resultList) {
            LambdaQueryWrapper<GroupTestDetail> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(GroupTestDetail::getSerialCode, result.getGroupCode());
            GroupTestDetail groupTestDetail = groupTestDetailPlusService.getOne(queryWrapper);

            Map<String,Object> map = new LinkedHashMap<>();
            map.put("二维码编号", Objects.isNull(groupTestDetail) ? 0 : groupTestDetail.getSerialNumber());
            map.put("姓名", result.getWxRealName());
            map.put("手机号", result.getMobile());
            map.put("openId", result.getWxId());
            map.put("昵称", result.getWxName());
            map.put("特质类型", result.getAtmrResultType());
            map.put("测评时间", result.getExamTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list,UUID.fastUUID().toString(true), response);
    }
}